import cv2
import pyzbar.pyzbar as pyzbar
import numpy as np
import health
import PyQt5.QtWidgets as qw
import PyQt5.QtCore as qc
import PyQt5.QtGui as qg
import logging
import threading
import winsound

class Health(qw.QWidget, health.Ui_Form):   #创建主界面类
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        # OpenCV
        self.cap = cv2.VideoCapture()

        # 图像捕获
        self.isExternalCameraUsed = 0  # 0为不使用外接摄像头，1为使用外接摄像头
        self.cam_status = 0  # 0未未打开摄像头
        self.checkBox_external.stateChanged.connect(self.checkBox_external_cb)
        self.btn_open_camera.clicked.connect(self.startWebcam)

        # 定时器
        self.timer = qc.QTimer(self)
        self.timer.timeout.connect(self.updateFrame)

        # set green thresh
        self.lower_green = np.array([35, 43, 46])
        self.upper_green = np.array([77, 255, 255])

        # set red thresh
        self.lower_red = np.array([0, 43, 46])
        self.upper_red = np.array([10, 255, 255])

        #是否开启报警
        self.status = False
        p = threading.Thread(target=self.bellProcess, daemon=True)  # 开启线程
        p.start()

    def checkBox_external_cb(self):  # 设置外接摄像头chekBox槽函数
        if self.checkBox_external.isChecked():
            self.isExternalCameraUsed = 1
        else:
            self.isExternalCameraUsed = 0

    # 打开/关闭摄像头
    def startWebcam(self):
        if (self.cam_status == 0):
            self.cam_status = 1
            if (self.isExternalCameraUsed == 1):
                camID = 1
            else:
                camID = 0
            self.cap.open(camID)
            self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 641)  # 设置图像宽度
            self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 501)  # 设置图像高度
            ret, frame = self.cap.read()
            # print(ret)
            if not ret:
                logging.error('无法调用电脑摄像头{}'.format(camID))
                self.logQueue.put('Error：初始化摄像头失败')
                self.cap.release()
                self.btn_open_camera.setChecked(False)
            else:
                self.btn_open_camera.setText('结束检测')
                self.timer.start(5)
        else:
            if self.cap.isOpened():
                if self.timer.isActive():
                    self.timer.stop()
                self.cap.release()
                self.label.clear()
                self.label.setText('<font color=red>未开启检测</font>')
                self.btn_open_camera.setText('开始检测')

    # 定时器，实时更新画面
    def updateFrame(self):
        ret, frame = self.cap.read()
        # self.image = cv2.flip(self.image, 1)
        if ret:
            self.displayImage(frame)
            self.decodeDisplay(frame)


    # 显示图像
    def displayImage(self, img):
        # BGR -> RGB
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # default：The image is stored using 8-bit indexes into a colormap， for example：a gray image
        qformat = qg.QImage.Format_Indexed8

        if len(img.shape) == 3:  # rows[0], cols[1], channels[2]
            if img.shape[2] == 4:
                # The image is stored using a 32-bit byte-ordered RGBA format (8-8-8-8)
                # A: alpha channel，不透明度参数。如果一个像素的alpha通道数值为0%，那它就是完全透明的
                qformat = qg.QImage.Format_RGBA8888
            else:
                qformat = qg.QImage.Format_RGB888

        # img.shape[1]：图像宽度width，img.shape[0]：图像高度height，img.shape[2]：图像通道数
        # QImage.__init__ (self, bytes data, int width, int height, int bytesPerLine, Format format)
        # 从内存缓冲流获取img数据构造QImage类
        # img.strides[0]：每行的字节数（width*3）,rgb为3，rgba为4
        # strides[0]为最外层(即一个二维数组所占的字节长度)，strides[1]为次外层（即一维数组所占字节长度），strides[2]为最内层（即一个元素所占字节长度）
        # 从里往外看，strides[2]为1个字节长度（uint8），strides[1]为3*1个字节长度（3即rgb 3个通道）
        # strides[0]为width*3个字节长度，width代表一行有几个像素

        outImage = qg.QImage(img, img.shape[1], img.shape[0], img.strides[0], qformat)
        self.label.setPixmap(qg.QPixmap.fromImage(outImage))
        self.label.setScaledContents(True)


    def decodeDisplay(self,video):
        # 转为灰度图像
        gray = cv2.cvtColor(video, cv2.COLOR_BGR2GRAY)
        # cv2.imshow("gray",gray)
        barcodes = pyzbar.decode(gray) #二维码解析的信息


        for barcode in barcodes:
            # 提取二维码的位置,然后用边框标识出来在视频中
            (x, y, w, h) = barcode.rect
            cv2.rectangle(video, (x, y), (x + w, y + h), (0, 255, 0), 2)
            # 字符串转换
            barcodeData = barcode.data.decode("utf-8") #二维码的data信息
            barcodeType = barcode.type
            # 在图像上面显示识别出来的内容
            text = "{}".format(barcodeData)
            cv2.putText(video, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
            data = barcodeData[10:13]
            data1 = barcodeData[0:3]

            # 打印识别后的内容
            print("[扫描结果] 二维码类别： {0} 内容： {1}".format(barcodeType, barcodeData))
            #print(data1)

            if data == "yss":
                # get a frame and show

                # cv2.imshow('Capture', frame)
                #print("data")
                # change to hsv model
                hsv = cv2.cvtColor(video, cv2.COLOR_BGR2HSV)

                # get mask

                mask = cv2.inRange(hsv, self.lower_green, self.upper_green)
                mask1 = cv2.inRange(hsv, self.lower_red, self.upper_red)
                # cv2.imshow('Mask', mask)

                # detect green/red
                res = cv2.bitwise_and(video, video, mask=mask)
                #res1 = cv2.bitwise_and(video, video, mask1=mask1)
                # cv2.imshow('Result', res)
                #cv2.imshow('Result1',res1)

                img_hsv = cv2.cvtColor(video, cv2.COLOR_BGR2HSV)
                mask_green = cv2.inRange(img_hsv, self.lower_green, self.upper_green)  # 获得绿色部分掩膜
                mask_red = cv2.inRange(img_hsv, self.lower_red, self.upper_red)  # 可以认为是过滤出红色部分，获得红色的掩膜

                mask_green = cv2.medianBlur(mask_green, 7)  # 中值滤波
                mask_red = cv2.medianBlur(mask_red, 7)  # 中值滤波
                mask = cv2.bitwise_or(mask_green, mask_red)  # 三部分掩膜进行按位或运算
                #mask1 = cv2.bitwise_or(mask_red, mask_green)  # 三部分掩膜进行按位或运算
                cnts1, hierarchy1 = cv2.findContours(mask_green, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

                red_areas = 0.0 # 图片中红色物体矩形框面积
                green_areas = 0.0  # 图片中绿色物体矩形框面积
                total_areas = video.shape[0] * video.shape[1]  # 图片总面积
                for cnt in cnts1:
                    (x, y, w, h) = cv2.boundingRect(cnt)  # 该函数返回矩阵四个点
                    green_areas += w * h
                green_percentage = green_areas / total_areas  # 绿色占比
                red_percentage = red_areas / total_areas  #红色占比

                if green_percentage > 0.05:
                    print("green")
                    self.status = False
                    tips = '当前检测粤康码为：<font color=green>{}</font> 。'.format("绿码")
                    qw.QMessageBox.information(self, "提示", tips)

                if red_percentage > 0.1:
                    print("red")
                    self.status = True
                    tips = '当前检测粤康码为：<font color=red>{}</font> 。'.format("红码")
                    qw.QMessageBox.warning(self, "警告", tips)

            if data1 == "粤康码":
                print(data1)
                # get a frame and show

                # cv2.imshow('Capture', frame)
                # print("data")
                # change to hsv model
                hsv = cv2.cvtColor(video, cv2.COLOR_BGR2HSV)

                # get mask 改变显示红色还是绿色
                #mask = cv2.inRange(hsv, lower_green, upper_green)
                mask = cv2.inRange(hsv, self.lower_red, self.upper_red)
                # cv2.imshow('Mask', mask)

                # detect green/red
                res = cv2.bitwise_and(video, video, mask=mask)
                # cv2.imshow('Result', res)


                img_hsv = cv2.cvtColor(video, cv2.COLOR_BGR2HSV)
                mask_green = cv2.inRange(img_hsv, self.lower_green, self.upper_green)  # 获得绿色部分掩膜
                mask_red = cv2.inRange(img_hsv, self.lower_red, self.upper_red)  # 可以认为是过滤出红色部分，获得红色的掩膜

                mask_green = cv2.medianBlur(mask_green, 7)  # 中值滤波
                mask_red = cv2.medianBlur(mask_red, 7)  # 中值滤波
                mask = cv2.bitwise_or(mask_green, mask_red)  # 三部分掩膜进行按位或运算
                # mask1 = cv2.bitwise_or(mask_red, mask_green)  # 三部分掩膜进行按位或运算
                cnts1, hierarchy1 = cv2.findContours(mask_green, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
                cnts2, hierarchy2 = cv2.findContours(mask_red, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

                red_areas = 0.0  # 图片中红色物体矩形框面积
                green_areas = 0.0  # 图片中绿色物体矩形框面积
                total_areas = video.shape[0] * video.shape[1]  # 图片总面积
                for cnt in cnts1:
                    (x, y, w, h) = cv2.boundingRect(cnt)  # 该函数返回矩阵四个点
                    green_areas += w * h
                for cnt in cnts2:
                    (x, y, w, h) = cv2.boundingRect(cnt)  # 该函数返回矩阵四个点
                    red_areas += w * h
                green_percentage = green_areas / total_areas  # 绿色占比
                red_percentage = red_areas / total_areas  # 红色占比

                if green_percentage > 0.05:
                    print("green")
                    self.status = False
                    tips = '当前检测粤康码为：<font color=green>{}</font> 。'.format("绿码")
                    qw.QMessageBox.information(self, "提示", tips)

                if red_percentage > 0.5:
                    print("red")
                    self.status = True
                    tips = '当前检测粤康码为：<font color=red>{}</font> 。'.format("红码")
                    qw.QMessageBox.warning(self,"警告",tips)


    # 设备响铃进程
    def bellProcess(self):
        while True:
            if self.status:
                self.status = False
                logging.warning('系统发出了报警信号')
                winsound.PlaySound('./alarm.wav', winsound.SND_FILENAME)
